# coding=utf-8
import hashlib
import json
import os
import re
import subprocess
import sys
from time import sleep
import time
import threading
from PyQt4 import QtGui, QtCore
from qiniu import Auth, BucketManager, build_batch_delete, put_file
from articalCreater import ArticalCreater
from fileCompire import Compiror
from tools import Tools
from ui import resource_path
from ui.main_ui import Ui_MainWindow
from ui.manage_info_window import Ui_window



class MyWindow(QtGui.QMainWindow):
    pass


class sync_All_now(QtCore.QThread):
    log = QtCore.pyqtSignal(str)

    def __init__(self, sync_now, bucket_manager, bucket, src, auth, popo):
        super(sync_All_now, self).__init__(None)
        self.sync_now = sync_now
        self.bucket_manager = bucket_manager
        self.bucket = bucket
        self.src = src
        self.auth = auth
        self.popo = popo

    def run(self):
        self.sync_now.setEnabled(False)
        local_files = Tools.getAllFiles(self.src)
        remote_files = []

        eof = False
        marker = None

        while eof is False:
            ret, eof, info = self.bucket_manager.list(self.bucket, marker=marker)
            print ret
            marker = ret.get('marker', None)
            for item in ret['items']:
                key = item['key']
                remote_files.append(Tools.decode(key, 'utf8'))
        print 'remote: ', remote_files
        print 'local:', local_files
        # 删除文件
        del_list = Tools.cmpDelFiles(remote_files, local_files)
        for i, li in enumerate(del_list):
            print isinstance(li, str)
            self.log.emit(u'del:' + li)
            del_list[i] = Tools.encode(li, 'utf8')
            print 'del:', li
        if len(del_list) > 0:
            ops = build_batch_delete(self.bucket, del_list)
            ret, info = self.bucket_manager.batch(ops)

        add_list = Tools.cmpAddFiles(remote_files, local_files)

        dic_add = None
        try:
            f = open(os.path.join(self.src, '.sunjian/update.json'), 'r')
            dic = json.loads(f.read())
            dic_add = dic['add']
            add_list_set = set(add_list) | set(dic_add)
            add_list = list(add_list_set)
            f.close()
        except IOError, e:
            print 'IOError', e
        print add_list
        add_list.append('/.sunjian/list.json')
        # 添加文件
        for li in add_list:
            # 验证是否符合上传条件
            if isinstance(li, str):
                li = Tools.decode(li, 'utf8')
            localfile_path = os.path.join(self.src, li[1:])
            if isinstance(localfile_path, str):
                localfile_path = Tools.decode(localfile_path, 'utf8')
            if not os.path.exists(localfile_path) or Tools.is_ignore(localfile_path):
                continue
            # 开始上传啦
            key = li
            print 'add:', li, localfile_path
            self.log.emit(u'add:' + li)
            mime_type = "application/octet-stream"
            token = self.auth.upload_token(self.bucket, Tools.encode(key, 'utf8'))
            ret, info = put_file(token, key, localfile_path, mime_type=mime_type, check_crc=True)
            print ret
        # 去除update.json文件
        try:
            f = open(os.path.join(self.src, '.sunjian/update.json'), 'r')
            dic = json.loads(f.read())
            dic_add_new = dic['add']

            dic_add_new = Tools.cmpAddFiles(dic_add, dic_add_new)
            dic['add'] = dic_add_new
            json.dump(dic, open(os.path.join(self.src, ".sunjian/update.json"), 'w'))
            f.close()
        except IOError, e:
            print 'IOError', e

        self.popo.showMessage(u"同步完成", "", icon=1)
        self.sync_now.setEnabled(True)
        self.log.emit(u'同步完成.')

    local_files = None


class MyMain(Ui_MainWindow):
    isSync = True
    src = None
    user_home = os.path.expanduser('~')
    conf_path = os.path.join(user_home, '.sunjian/conf/')

    def init_popo(self, MainWindow):
        icon = QtGui.QIcon(resource_path('./libs/img/button_ico.jpg'))
        self.popo = QtGui.QSystemTrayIcon(MainWindow)
        self.popo.setIcon(icon)
        self.popo.show()

        # 设置菜单
        quitAction = QtGui.QAction(u"退出", MainWindow,
                                   triggered=self.quit_clicked)
        sync_nowAction = QtGui.QAction(u"立即同步", MainWindow,
                                       triggered=self.sync_now_clicked)
        createAction = QtGui.QAction(u"创建文章", MainWindow,
                                     triggered=self.create_art_clicked)
        # sync_startAction = QtGui.QAction(u"开始自动同步", MainWindow,
        #                                  triggered=self.sync_start_clicked)
        # sync_stopAction = QtGui.QAction(u"停止自动同步", MainWindow,
        #                                 triggered=self.sync_stop_clicked)

        self.trayIconMenu = QtGui.QMenu(MainWindow)

        # self.trayIconMenu.addAction(sync_startAction)
        # self.trayIconMenu.addAction(sync_stopAction)
        self.trayIconMenu.addAction(createAction)
        self.trayIconMenu.addAction(sync_nowAction)
        self.trayIconMenu.addAction(quitAction)
        self.popo.setContextMenu(self.trayIconMenu)
        # 设置点击图标
        self.popo.activated.connect(self.click_ico)

        print 'show'

    def click_ico(self, reason):
        if reason == QtGui.QSystemTrayIcon.Trigger:

            self.MainWindow.show()
            self.MainWindow.raise_()
        else:
            pass

    def quit_clicked(self):
        # self.sync_stop_clicked()
        self.popo.showMessage(u"Bye ~", "", icon=1)
        sys.exit(app.exec_())

    def log(self, txt):
        self.textBrowser.append(txt)

    def init_settings(self):
        try:
            if not os.path.exists(self.conf_path):
                print 'not exists'
                return
            else:
                print 'exist'
            f = open(self.conf_path+'myconf.json', 'r')

            d = json.loads(f.read())
            # self.src = str(d['src'])
            # self.access_key = str(d['access_key'])
            # self.secret_key = str(d['secret_key'])
            # self.bucket = str(d['bucket'])

            self.src = d.get("src", "")
            self.access_key = d.get("access_key", "")
            self.secret_key = d.get("secret_key", "")
            self.bucket = Tools.encode(d.get("bucket", ""), 'utf8')

            self.blog_path_input.setText(self.src)
            self.access_key_input.setText(self.access_key)
            self.secrete_key_input.setText(self.secret_key)
            self.bucket_input.setText(self.bucket)

            self.auth = Auth(Tools.encode(self.access_key, 'utf8'), Tools.encode(self.secret_key, 'utf8'))
            self.bucket_manager = BucketManager(self.auth)

            # self.init_popo()
        except IOError, e:
            print e
        except ValueError, e:
            print e

    def setupUi(self, MainWindow):
        Ui_MainWindow.setupUi(self, MainWindow)
        self.MainWindow = MainWindow
        self.watch_btn.clicked.connect(self.watch_btn_clicked)
        self.save_btn.clicked.connect(self.save_btn_clicked)
        self.sync_start.clicked.connect(self.sync_start_clicked)
        self.sync_stop.clicked.connect(self.sync_stop_clicked)
        self.sync_now.clicked.connect(self.sync_now_clicked)
        self.create_art.clicked.connect(self.create_art_clicked)
        self.action.connect(self.headInfoAction, QtCore.SIGNAL("triggered()"), self.headInfo_action_clicked)
        self.action.connect(self.action, QtCore.SIGNAL("triggered()"), self.add_info_for_all_file)
        self.init_settings()
        self.init_popo(MainWindow)
        if self.src and self.access_key and self.secret_key:
            # 设置好同步文件夹的路径和七牛云的相关信息开始监控文件夹的变化
            self.start_monitor()
        else:
            self.tabWidget.setCurrentIndex(1)
            self.tab.setEnabled(False)

    # 开始监控同步文件夹的变化
    def start_monitor(self):
        self.init_create_file()
        # u = UpDataer(self.src)
        # u.start()

    def headInfo_action_clicked(self):
        if not hasattr(self, "headinfo_window"):
            self.headinfo_window = MyWindow()
        if not hasattr(self, "ui_form"):
            self.ui_form = Ui_window()
        Compiror.initCompire(self.src)
        self.ui_form.setupUi(self.headinfo_window)
        self.ui_form.fileTreeWidget.connect(self.ui_form.fileTreeWidget,
                                            QtCore.SIGNAL('itemClicked(QTreeWidgetItem*, int)'),
                                            self.tree_item_on_click)
        self.init_treeview(self.src, self.ui_form.fileTreeWidget)
        self.ui_form.saveButton.clicked.connect(self.headinfo_window_save_btn_clicked)
        self.headinfo_window.show()

    def init_treeview(self, src, parent):
        tree_item_dict = {src: parent}
        for root, dirs, files in os.walk(src):
            root = Tools.replace_backslash(root)
            if not Tools.filter_ignored_folder(root):
                continue
            parent_item = tree_item_dict[root]
            for d in filter(Tools.filter_ignored_folder, dirs):
                item = QtGui.QTreeWidgetItem(parent_item, [d])
                tree_item_dict.update({Tools.join_path(root, d): item})
            for f in filter(Tools.filter_hold_file, files):
                item = QtGui.QTreeWidgetItem(parent_item, [f])
                item.path = Tools.remove_prefix(self.src, Tools.join_path(root, f))

    def tree_item_on_click(self, item, column):
        save_btn = self.ui_form.saveButton
        save_btn.setEnabled(True)
        head_info_table_widget = self.ui_form.headInfoTableWidget
        if not hasattr(item, "path"):
            save_btn.setEnabled(False)
            head_info_table_widget.setRowCount(0)
            return
        head_info_dict = json.load(open(Tools.join_path(self.src, ".sunjian/list.json")))
        index = 0
        head_info_table_widget.setRowCount(0)
        head_info_table_widget.setRowCount(len(head_info_dict[item.path].keys()))
        print head_info_dict[item.path].keys()

        def on_delete_btn_clicked(item):
            if item.column() == 0:
                head_info_table_widget.removeRow(item.row())

        for key in head_info_dict[item.path].keys():
            key_item = QtGui.QTableWidgetItem(key)
            key_item.setTextAlignment(QtCore.Qt.AlignCenter)
            value_item = QtGui.QTableWidgetItem(head_info_dict[item.path][key])
            value_item.setTextAlignment(QtCore.Qt.AlignCenter)
            if key == "hash":
                continue
            if key == "id":
                key_item.setFlags(QtCore.Qt.NoItemFlags)
                value_item.setFlags(QtCore.Qt.NoItemFlags)
            del_item = QtGui.QTableWidgetItem("delete")
            del_item.setTextAlignment(QtCore.Qt.AlignCenter)
            head_info_table_widget.setItem(index, 0, del_item)
            head_info_table_widget.setItem(index, 1, key_item)
            head_info_table_widget.setItem(index, 2, value_item)
            head_info_table_widget.itemClicked.connect(on_delete_btn_clicked)
            index += 1
        # 下面的代码是在最后一行添加一个add按钮，由于要让其居中，所以代码较多
        head_info_table_widget.setSpan(index, 0, 1, 3)
        layout = QtGui.QHBoxLayout()
        btn = QtGui.QPushButton("add")
        btn.setFixedWidth(100)
        layout.addWidget(btn)
        layout.setMargin(0)
        layout.setAlignment(QtCore.Qt.AlignCenter)
        widget = QtGui.QWidget(head_info_table_widget)
        widget.setLayout(layout)
        head_info_table_widget.setCellWidget(index, 0, widget)

        def add_one_row():
            head_info_table_widget.insertRow(head_info_table_widget.rowCount() - 1)
            del_item = QtGui.QTableWidgetItem("delete")
            del_item.setTextAlignment(QtCore.Qt.AlignCenter)
            head_info_table_widget.setItem(head_info_table_widget.rowCount() - 2, 0, del_item)
        btn.clicked.connect(add_one_row)

    def headinfo_window_save_btn_clicked(self):
        d = {}
        head_info_table_widget = self.ui_form.headInfoTableWidget
        for index in range(head_info_table_widget.rowCount() - 1):
            key_item = head_info_table_widget.item(index, 1)
            value_item = head_info_table_widget.item(index, 2)
            if key_item and value_item:
                key = key_item.text()
                value = value_item.text()
                print key, value
            else:
                continue
            d.update({str(key.toUtf8()).decode("utf8"): str(value.toUtf8()).decode("utf8")})
        path = self.ui_form.fileTreeWidget.currentItem().path
        self.add_info_for_file(path, d)
        try:
            json_dict = json.load(open(os.path.join(self.src, ".sunjian/list.json"), "r"))
        except Exception:
            json_dict = {}
        if not json_dict:
            json_dict.update({Tools.remove_prefix(self.src, path): d})
        else:
            d.update({"hash": json_dict[Tools.remove_prefix(self.src, path)]["hash"]})
            json_dict[Tools.remove_prefix(self.src, path)] = d
        json.dump(json_dict, open(os.path.join(self.src, ".sunjian/list.json"), "w"))

    def save_btn_clicked(self):
        # QString,myconf.json中的同步文件夹路径也用正斜杠
        src = Tools.replace_backslash(str(self.blog_path_input.text().toUtf8()))
        access_key = str(self.access_key_input.text().toUtf8())
        secret_key = str(self.secrete_key_input.text().toUtf8())
        bucket = str(self.bucket_input.text().toUtf8())
        # qiniu_settings = """{
        #     "src": "%s",
        #     "dest": "qiniu:access_key=%s&secret_key=%s&bucket=%s",
        #     "debug_level": 1
        # }""" % (src, access_key, secret_key, bucket)
        qiniu_settings = {
            "src": src,
            "dest": "qiniu:access_key=%s&secret_key=%s&bucket=%s" % (access_key, secret_key, bucket),
            "debug_level": 1
        }
        my_settings = {
            "src": src,
            "access_key": access_key,
            "secret_key": secret_key,
            "bucket": bucket
        }
        if not os.path.exists(self.conf_path):
            os.makedirs(self.conf_path)
        f = open(self.conf_path+'conf.json', 'w')
        # f.write(qiniu_settings)
        f.write(json.dumps(qiniu_settings))
        f.close()
        f = open(self.conf_path+'myconf.json', 'w')
        f.write(json.dumps(my_settings))
        f.close()
        self.init_settings()
        self.popo.showMessage(u"已保存设置", "", icon=1)
        if src and access_key and secret_key:
            self.tabWidget.setCurrentIndex(0)
            self.tab.setEnabled(True)
            self.init_settings()
            self.start_monitor()

    def watch_btn_clicked(self):
        selectDirName = QtGui.QFileDialog.getExistingDirectory(None, u"选择博客路径", "/home")
        self.blog_path_input.setText(selectDirName)

    def syncIt(self):
        my_path = os.getcwd()
        if self.isSync:
            p = subprocess.Popen(
                'qrsboxcli init %s %s %s %s' % (self.access_key, self.secret_key, self.src, self.bucket),
                cwd='%s/libs' % my_path, shell=True, stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT)
            p = subprocess.Popen(
                'qrsboxcli sync',
                cwd='%s/libs' % my_path, shell=True, stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT)
            p = subprocess.Popen(
                'qrsboxcli log',
                cwd='%s/libs' % my_path, shell=True, stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT)
            print 'logs:'
            logs = ''.join(p.stdout.readlines())
            print logs
            # textBrowser.append(logs.decode('gbk'))

    def sync_now_clicked(self):
        Compiror.initCompire(self.src)
        self.sync_thread = sync_All_now(self.sync_now, self.bucket_manager, self.bucket, self.src, self.auth, self.popo)
        self.sync_thread.log.connect(self.log)
        self.sync_thread.start()
        self.log(u'正在同步...')
        self.popo.showMessage(u"正在同步", "", icon=1)

    def watchDel(self):
        while self.isSync:
            file_list = Tools.getAllFiles(self.src)
            if self.local_files is not None:

                del_list = Tools.cmpDelFiles(self.local_files, file_list)

                # print del_list
                if len(del_list) > 0:
                    ops = build_batch_delete(self.bucket, del_list)
                    ret, info = self.bucket_manager.batch(ops)
                    # print info

            self.local_files = file_list

            sleep(5)

    # 假定path存在prefix
    def is_exist_header(self, path):
        with open(path, 'r+') as f:
            d = {}
            while True:
                line = f.readline()
                if not line:
                    break
                if line.replace(" ", "") == "":
                    continue
                if ":" not in line:
                    break
                key = line.split(":", 1)[0].strip()
                value = line.split(":", 1)[1].strip()
                d.update(dict({key: value}))
        if d:
            return True
        else:
            return False

    def add_info_for_file(self, path, info_dict=None):
        path = Tools.decode(path, 'utf8')
        path = Tools.add_prefix(self.src, path)
        if info_dict:
            with open(path, "r+") as f:
                content = re.split(r"\n-+\n", f.read(), 1)
                if len(content) > 1:
                    content = content[1]
                else:
                    content = content[0]
                f.seek(0, 0)
                for key in info_dict:
                    f.write((key + ":" + info_dict[key]).encode("utf8") + "\n")
                f.write("\n---\n")
                f.write(content)
            return
        if not self.is_exist_header(path):
            with open(path, 'r+') as f:
                content = f.read()
                t = os.path.getctime(path)
                time_format = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t))
                time_format_md5 = hashlib.md5(time_format)
                f.seek(0, 0)
                f.write("id : " + time_format_md5.hexdigest() + "\n")
                f.write("date : " + time_format + "\n")
                f.write("hash :" + hashlib.md5(content).hexdigest())
                f.write("\n---\n")
                f.write(content)

    def add_info_for_all_file(self):
        src = self.src
        files = Tools.getAllFilesIngored(src)
        for file in files:
            self.add_info_for_file(file)
        self.log("done")

    def sync_start_clicked(self):
        self.isSync = True
        thread = threading.Thread(target=self.syncIt)
        thread.start()

        thread = threading.Thread(target=self.watchDel)
        thread.start()

        self.log(u'开始同步...')
        self.popo.showMessage(u"开始同步...", "", icon=1)

    def sync_stop_clicked(self):
        self.isSync = False
        # os.system('taskkill /f /im qrsboxcli.exe')
        self.log(u'停止同步')
        self.popo.showMessage(u"已停止同步", "", icon=1)

    def create_art_clicked(self):
        self.ArtWindow = QtGui.QMainWindow()
        self.ui = ArticalCreater(self.src)
        self.ui.setupUi(self.ArtWindow)
        self.ArtWindow.show()

    def init_create_file(self):
        p = os.path.join(self.src, ".sunjian")
        if not os.path.exists(p):
            os.mkdir(p)
        if not os.path.exists(os.path.join(p, "list.json")):
            f = open(os.path.join(p, "list.json"), "w")
            f.close()
        if not os.path.join(p, "update.json"):
            f = open(os.path.join(p, "update.json"), "w")
            f.close()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    MainWindow = MyWindow()
    ui = MyMain()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())


class MyApplication(QtGui.QApplication):
    # 每一个app拥有一个main_window，也就是程序运行时的第一个窗口
    main_window = None
    # 一个程序的其他的windows，用一个字典存储，key是向application注册时的名字，value是window对象
    other_windows = {}

    def __init__(self, list_of_str, main_window):
        super(MyApplication, self).__init__(list_of_str)
        self.register_main_window(main_window)

    def register_main_window(self, main_window):
        self.main_window = main_window

    def get_main_window(self):
        return self.main_window

    def register_window(self, window, window_name):
        self.other_windows.update({window_name: window})

    def get_window(self, window_name):
        return self.other_windows.get(window_name, None)

    def start(self):
        self.main_window.show()
        sys.exit(self.exec_())
